package com.zmzncs.lmtc.module.customer.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.zmzncs.lmtc.common.pojo.bolian.PaymonthcardRes;
import com.zmzncs.lmtc.common.pojo.daoer.MonthlyCarInfoRes;
import com.zmzncs.lmtc.common.pojo.tengda.CarForm;
import com.zmzncs.lmtc.common.pojo.tengda.TengdaForm;
import com.zmzncs.lmtc.common.util.BolianUtil;
import com.zmzncs.lmtc.common.util.WeChatUtil;
import com.zmzncs.lmtc.common.util.MpMessageUtil;
import com.zmzncs.lmtc.common.pojo.LoginUser;
import com.zmzncs.lmtc.common.pojo.enums.PayStatusEnum;
import com.zmzncs.lmtc.common.pojo.enums.WhetherEnum;
import com.zmzncs.lmtc.common.pojo.enums.optionalvalue.card.CardTypeEnum;
import com.zmzncs.lmtc.common.pojo.enums.optionalvalue.card.RealtimeCardTypeEnum;
import com.zmzncs.lmtc.common.pojo.enums.optionalvalue.order.OrderCardTypeEnum;
import com.zmzncs.lmtc.common.pojo.enums.optionalvalue.promotion.MonthRentTypeEnum;
import com.zmzncs.lmtc.common.pojo.mpMessage.OpenServiceMessage;
import com.zmzncs.lmtc.common.pojo.mpMessage.RechargeSuccess;
import com.zmzncs.lmtc.common.util.*;
import com.zmzncs.lmtc.common.websocket.WebsocketServer;
import com.zmzncs.lmtc.module.customer.dao.*;
import com.zmzncs.lmtc.module.customer.pojo.car.Car;
import com.zmzncs.lmtc.module.customer.pojo.car.CarDTO;
import com.zmzncs.lmtc.module.customer.pojo.card.*;
import com.zmzncs.lmtc.module.customer.pojo.card_park.CardPark;
import com.zmzncs.lmtc.module.customer.pojo.card_record.CardRecord;
import com.zmzncs.lmtc.module.customer.pojo.card_record.CardRecordDTO;
import com.zmzncs.lmtc.module.customer.pojo.card_record_park.CardRecordPark;
import com.zmzncs.lmtc.module.customer.pojo.card_record_park.CardRecordParkDTO;
import com.zmzncs.lmtc.module.customer.pojo.cardmonthrecord.CardMonthRecord;
import com.zmzncs.lmtc.module.customer.pojo.cardmonthrecord.CardMonthRecordDTO;
import com.zmzncs.lmtc.module.customer.pojo.customer.Customer;
import com.zmzncs.lmtc.module.customer.pojo.customer.CustomerDTO;
import com.zmzncs.lmtc.module.customer.pojo.ticket.CustTicketDTO;
import com.zmzncs.lmtc.module.customer.service.CardService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zmzncs.lmtc.module.order.dao.OrderCardDao;
import com.zmzncs.lmtc.module.order.dao.OrderInfoDao;
import com.zmzncs.lmtc.module.order.dao.OrderTradeRecordDao;
import com.zmzncs.lmtc.module.park.dao.ParkInfoDao;
import com.zmzncs.lmtc.module.park.dao.ParkInfoDaoerDao;
import com.zmzncs.lmtc.module.park.pojo.park_info_daoer.ParkInfoDaoer;
import com.zmzncs.lmtc.module.park.pojo.parkinfo.ParkInfo;
import com.zmzncs.lmtc.module.promotion.dao.*;
import com.zmzncs.lmtc.module.promotion.pojo.customize_rule_fee_scale.CustomizeRuleFeeScaleDTO;
import com.zmzncs.lmtc.module.promotion.pojo.customize_rule_fee_scale.CustomizeRuleFeeScaleMobileVO;
import com.zmzncs.lmtc.module.promotion.pojo.duration_rule_fee_scale.DurationRuleFeeScaleDTO;
import com.zmzncs.lmtc.module.promotion.pojo.duration_rule_park.DurationRuleParkDTO;
import com.zmzncs.lmtc.module.promotion.pojo.month_rule_fee_scale.MonthRuleFeeScaleDTO;
import com.zmzncs.lmtc.module.promotion.pojo.month_rule_pull.MonthRulePull;
import com.zmzncs.lmtc.module.promotion.service.CustomizeRuleService;
import com.zmzncs.lmtc.module.customer.dao.CustTicketDao;
import com.zmzncs.lmtc.module.promotion.dao.TicketDao;
import com.zmzncs.lmtc.module.customer.pojo.ticket.CustTicket;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.LongValue;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 客户-会员卡 服务实现类
 * </p>
 *
 * @author 任建波
 * @since 2020-09-02
 */
@Slf4j
@Service
public class CardServiceImpl extends ServiceImpl<CardDao, Card> implements CardService {

    @Autowired
    CarDao carDao;
    @Autowired
    CardDao cardDao;
    @Autowired
    CustomerDao customerDao;
    @Autowired
    CardRecordDao cardRecordDao;
    @Autowired
    OrderInfoDao orderInfoDao;
    @Autowired
    TicketDao ticketDao;
    @Autowired
    CustTicketDao custTicketDao;
    @Autowired
    CardRecordParkDao cardRecordParkDao;
    @Autowired
    MonthRuleMapper monthRuleMapper;
    @Autowired
    MonthRuleParkMapper monthRuleParkMapper;
    @Autowired
    MonthRuleFeeScaleMapper monthRuleFeeScaleMapper;
    @Autowired
    CardParkDao cardParkDao;
    @Autowired
    CustomizeRuleFeeScaleDao customizeRuleFeeScaleDao;
    @Autowired
    CustomizeRuleService customizeRuleService;
    @Autowired
    CustomizeRuleDao customizeRuleDao;
    @Autowired
    DurationRuleMapper durationRuleMapper;
    @Autowired
    DurationRuleParkMapper durationRuleParkMapper;
    @Autowired
    DurationRuleFeeScaleMapper durationRuleFeeScaleMapper;
    @Autowired
    OrderCardDao orderCardDao;
    @Autowired
    ParkInfoDao parkInfoDao;
    @Autowired
    MpMessageUtil mpMessageUtil;
    @Autowired
    OrderTradeRecordDao orderTradeRecordDao;
    @Autowired
    ParkInfoDaoerDao parkInfoDaoerDao;
    @Autowired
    CardMonthRecordDao cardMonthRecordDao;
    @Autowired
    MonthRulePullDao monthRulePullDao;


    @Autowired
    HttpServletRequest request;
    @Autowired
    WebsocketServer websocketServer;

    @Value("${pay-test}")
    boolean payTest;
    @Value("${wechat.notify-url.recharge}")
    String rechargeNotifyUrl;
    @Value("${wechat.notify-url.buyMonthCard}")
    String buyMonthCardNotifyUrl;
    @Value("${wechat.notify-url.buyCustomizeCard}")
    String buyCustomizeCardNotifyUrl;
    @Value("${wechat.notify-url.buyDurationCard}")
    String buyDurationCardNotifyUrl;

    //  请求队列
    private static List<String> requestCatch = new ArrayList();


    /**
     * 充值
     */
    @Override
    @Transactional
    public Map<String, Object> recharge(RechargeForm form) {
        //  优惠券
        CustTicketDTO custTicket = custTicketDao.getById(form.getCustTicketId());
        /*1、校验支付金额*/
        checkPaidAmount(form.getPaidAmount(), form.getReceivableAmount(), custTicket);

        //  登录信息
        LoginUser loginUser = JwtUtil.getLoginUser(request);
        CustomerDTO customerDTO = customerDao.getCustomerById(loginUser.getCustomerId());
        if(customerDTO == null){
            ExceptionUtil.businessException("客户：" + loginUser.getCustomerId() + "不存在");
        }

        //  订单号
        String orderCode = ChinaumsUtil.getMerOrderId("CZ");  //    订单号

        /*2、充值记录*/
        CardRecord cardRecord = new CardRecord();
        cardRecord.setCardType(4);
        cardRecord.setReceivableAmount(form.getReceivableAmount());
        cardRecord.setPaidAmount(form.getPaidAmount());
        cardRecord.setPayStatus(0);
        cardRecord.setCustomerId(loginUser.getCustomerId());
        cardRecord.setTicketId(form.getCustTicketId());
        cardRecord.setOrderCode(orderCode);
        cardRecord.setMobilePhone(customerDTO.getMobilePhone());
        cardRecordDao.insert(cardRecord);

        /*3、下单*/
        BigDecimal cost = payTest ? new BigDecimal("0.01"): form.getPaidAmount();
        JSONObject attach = new JSONObject();
        attach.put("custTicketId", form.getCustTicketId());
        Map<String, Object> wxPay = WeChatUtil.wxPay(customerDTO.getOpenid(), rechargeNotifyUrl, cost, orderCode, attach.toJSONString(), "充值");

        return wxPay;
    }

    /**
     * 微信支付回调-充值
     */
    @Override
    @Transactional
    public String rechargeCallback(String callbackStr) {
        //  解析微信返回值
        Map<String, String> callbackMap = null;
        try {
            callbackMap = XmlUtil.parseXML(callbackStr);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 支付成功
        if ("SUCCESS".equals(callbackMap.get("return_code")) && "SUCCESS".equals(callbackMap.get("result_code"))) {
            //  修改充值订单状态
            String orderCode = callbackMap.get("out_trade_no");    //  订单号
            log.info("订单号：" + orderCode);

            //  处理充值订单
            String attach = callbackMap.get("attach");  //  附加数据
            CardRecordDTO cardRecordDTO = cardRecordDao.getCardRecordByOrderCode(orderCode);
            if(cardRecordDTO == null) {
                log.error("订单号" + orderCode + "错误");
                return WeChatUtil.wxpayCallbackResult(true);
            }
            //  如果已经支付，返回true
            if(cardRecordDTO.getPayStatus() == PayStatusEnum.PAID.getCode()){
                log.info("订单号" + orderCode + "已经支付，不能重复支付");
                return WeChatUtil.wxpayCallbackResult(true);
            }
            attach = StringEscapeUtils.unescapeJava(attach);    //  在处理字符串之前，先将字符串去除转义
            JSONObject attachJB = JSONObject.parseObject(attach);
            String custTicketId = attachJB.getString("custTicketId");

            CardRecord cardRecord = new CardRecord();
            /*1、修改优惠券状态*/
            if(StringUtils.isNotBlank(custTicketId)){
                CustTicket custTicket = custTicketDao.selectById(Long.valueOf(custTicketId));
                if (custTicket != null){
                    custTicket.setStatus(1);
                    custTicket.setTipsStatus(0);
                    custTicket.setUpdateTime(new Date());
                    custTicketDao.updateById(custTicket);

                    cardRecord.setTicketId(custTicket.getTicketId());
                }
            }

            /*3、修改余额*/
            CardDTO cardDTO = cardDao.getBalance(cardRecordDTO.getCustomerId());
            Card card = new Card();
            if(cardDTO == null){
                card.setCustomerId(cardRecordDTO.getCustomerId());
                card.setCardType(4);
                card.setCardBalance(cardRecordDTO.getReceivableAmount());
                cardDao.insert(card);
                cardRecord.setCardId(card.getId());
            } else {
                cardRecord.setCardId(cardDTO.getId());
                card.setId(cardDTO.getId());
                card.setCardBalance(cardDTO.getCardBalance().add(cardRecordDTO.getReceivableAmount()));
                cardDao.updateById(card);
            }

            /*2、修改充值记录状态*/
            cardRecord.setId(cardRecordDTO.getId());
            cardRecord.setPayStatus(PayStatusEnum.PAID.getCode());
            cardRecordDao.updateById(cardRecord);

            /*4、公众号发送充值成功通知*/
            CustomerDTO customerDTO = customerDao.getCustomerById(cardRecordDTO.getCustomerId());
            if (customerDTO != null && customerDTO.getUnionid() != null) {
                RechargeSuccess message = new RechargeSuccess();
                message.setUnionid(customerDTO.getUnionid());
                BigDecimal receivableAmount = cardRecordDTO.getReceivableAmount();
                if (receivableAmount != null){
                    message.setRechargeAmount(receivableAmount.toString());
                }
                if(cardDTO == null){
                    message.setBalance(cardRecordDTO.getReceivableAmount().toString());
                } else {
                    message.setBalance(cardDTO.getCardBalance().add(cardRecordDTO.getReceivableAmount()).toString());
                }
                String rechargeTime = DateTimeUtil.convertYMDHMS(cardRecordDTO.getCreateTime());
                message.setRechargeTime(rechargeTime);
                message.setNickname(customerDTO.getNickname());

                String requestId = MDC.get("requestId");
                //充值成功通知
                mpMessageUtil.rechargeSuccess(message,requestId);
            }

            log.info("------------充值-微信支付回调结束");
        }

        return WeChatUtil.wxpayCallbackResult(true);
    }

    /**
     * 购买月卡
     */
    @Override
    @Transactional
    public Map<String, Object> buyMonthCard(MonthCardBuyForm form){
        LoginUser loginUser = JwtUtil.getLoginUser(request);

        /*  1、判断数据正确性   */
        String orderCode = ChinaumsUtil.getMerOrderId("YZK-");  //    订单号
        BigDecimal paidAmount = form.getPaidAmount();   //  支付金额
        //  查询客户
        CustomerDTO customerDTO = customerDao.getCustomerById(loginUser.getCustomerId());
        if(customerDTO == null){
            ExceptionUtil.businessException("客户：" + loginUser.getCustomerId() + "不存在");
        }
        if(StringUtils.isBlank(customerDTO.getMobilePhone())){
            ExceptionUtil.businessException("请绑定手机号");
        }
        //  根据规则id和月租类型查询收费标准
        MonthRuleFeeScaleDTO monthRuleFeeScaleDTO = monthRuleFeeScaleMapper.getMonthRuleFeeScaleByRuleIdAndMonthRentType(form.getMonthRuleId(), form.getMonthRentType(), form.getUniformRentType());
        if (monthRuleFeeScaleDTO == null) {
            ExceptionUtil.businessException("所选会员卡没有收费标准");
        }
        //  如果支付金额为0
        if(paidAmount.compareTo(new BigDecimal(0)) <= 0){
            ExceptionUtil.businessException("支付金额必须大于0");
        }

        /*1、优惠券*/
        CustTicketDTO custTicket = custTicketDao.getById(form.getCustTicketId());
        //  校验支付金额
        checkPaidAmount(paidAmount, monthRuleFeeScaleDTO.getAmount(), custTicket);

        //  停车场信息
        ParkInfo parkInfo = parkInfoDao.selectById(form.getParkId());
        //  当前到期时间
        Date currEndTime = DateTimeUtil.getDayEnd(new Date());
        //  开始时间
        Date startTime = DateTimeUtil.getStartOfDay(new Date());
        //  结束时间
        Date endTime;
        //  车牌
        Car car = carDao.selectById(form.getCarId());
        //  是否续卡
        String isRenewal = "0";
        //  支付停车场的金额
        BigDecimal paidParkAmount = paidAmount;
        //  月租编号
        String parkMonthId = "";

        /*2、如果monthRentType不为1、2、3，则为道尔、盒子等的月租*/
        if(!form.getMonthRentType().equals(1) && !form.getMonthRentType().equals(2) && !form.getMonthRentType().equals(3)){
            //  如果已经开始分润，计算支付停车场金额
            if(parkInfo.getMonthDivideBeginTime() != null && new Date().getTime() >= parkInfo.getMonthDivideBeginTime().getTime()){
                if(parkInfo.getMonthDivide() != null) {
                    //  月租分润金额（停车场月租 * 月租分润比率）
                    BigDecimal monthDivideAmount = monthRuleFeeScaleDTO.getAmount().multiply( parkInfo.getMonthDivide().divide(new BigDecimal(100)));
                    //  支付停车场月租金额（停车场月租金额 - 月租分润金额）
                    paidParkAmount =  form.getPaidAmount().subtract(monthDivideAmount);
                } else {
                    log.error("缺少分润比率，无法分润");
                }
            }

            /*1、计算会员卡开始结束时间*/
            //  道尔停车场车牌月租
            if(parkInfo.getParkSource().equals(3)){
                MonthlyCarInfoRes monthlycar = DaoerApiUtil.getMonthlycar(parkInfo.getBolianParkId(), car.getCarNumber());
                // 如果卡还未到期，续卡，如果卡还未到期，续卡
                if(monthlycar.getHead().getStatus().equals(1)){
                    //  月租编号相同则续卡，不同则不能同时两种卡开通，否则会覆盖已购买月租
                    if(monthlycar.getBody().getCardTypeId().equals(form.getMonthRentType())){
                        isRenewal = "1";
                        currEndTime = DateTimeUtil.fomatDateTime(monthlycar.getBody().getEndTime());
                        startTime = DateTimeUtil.fomatDateTime(monthlycar.getBody().getStartTime());
                        //  如果已过期，则销户，0
                    } else if(currEndTime.getTime() <= new Date().getTime()) {
                        DaoerApiUtil.monthDel(parkInfo.getBolianParkId(), car.getCarNumber());
                    //  不能同时两种卡开通
                    } else {
                        MonthRuleFeeScaleDTO monthRuleFeeScaleRep = monthRuleFeeScaleMapper.getMonthRuleFeeScaleByRuleIdAndMonthRentType(form.getMonthRuleId(), monthlycar.getBody().getCardTypeId(), form.getUniformRentType());
                        String monthRentName = monthRuleFeeScaleRep == null ? "" : monthRuleFeeScaleRep.getMonthRentName();
                        ExceptionUtil.businessException("车牌已购买" + monthRentName + "月租，不能同时开通" + monthRuleFeeScaleDTO.getMonthRentName());
                    }
                }
            }
            //  腾达停车场车牌月租
            if(parkInfo.getParkSource().equals(4)){
                //  查询车牌月租信息
                TengdaForm tengdaForm = TengdaUtil.monthCard(parkInfo.getBolianParkId(), car.getCarNumber(), null);
                if(tengdaForm.getCode().equals(0)) {
                    ExceptionUtil.businessException("查询腾达月租失败");
                }

                //  续卡
                if(tengdaForm.getCode().equals(1) && tengdaForm.getDataItems().size() > 0){
                    CarForm carForm = JSONObject.toJavaObject(tengdaForm.getDataItems().get(0), CarForm.class);

                    CarForm.Item item = carForm.getItems().get(0);
                    parkMonthId = item.getUUID();
                    currEndTime = DateTimeUtil.stringToDate(item.getTimeEnd());

                    //  不能同时开通两种卡
                    if(!item.getCarTypeCode().equals(form.getMonthRentType())){
                        ExceptionUtil.businessException("车牌已购买其他类型月租，请使用完后再开通该月租");
                    }
                    //  月租编号相同则续卡，并且未过期，或者不是临时卡，不同则不能同时开通两种卡，否则会覆盖已购买月租
                    if( ( item.getCarTypeCode().equals(form.getMonthRentType()) && currEndTime.getTime() > new Date().getTime() ) || ( item.getCarTypeCode() >= 91 && item.getCarTypeCode() <= 95 ) ){
                        isRenewal = "1";
                        currEndTime = DateTimeUtil.fomatDateTime(item.getTimeEnd());
                        startTime = DateTimeUtil.fomatDateTime(item.getTimeStart());
                    }
                    //  如果为白天卡或夜间卡，则到期取数据库数据，应为腾达白天夜间卡没有到期时间
                    if(form.getUniformRentType().equals(100) || form.getUniformRentType().equals(110)){
                        //  根据carId和parkId查询客户车辆服务
                        CardDTO cardDTO = cardDao.getCustomerCardByCarIdAndParkId(loginUser.getCustomerId(), form.getCarId(), form.getParkId());
                        if(cardDTO != null){
                            currEndTime = cardDTO.getExpireTime();
                            startTime = cardDTO.getStartTime();
                        }
                    }
                }
            }
        //  中萌自定义月租
        } else {
            /*1、计算到期日期*/
            //  根据carId和parkId查询客户车辆服务
            CardDTO cardDTO = cardDao.getCustomerCardByCarIdAndParkId(loginUser.getCustomerId(), form.getCarId(), form.getParkId());
            currEndTime = cardDTO.getExpireTime();
            startTime = cardDTO.getStartTime();
        }

        //  计算结束时间
        currEndTime = currEndTime.getTime() > new Date().getTime() ? currEndTime : new Date();
        //  如果是续卡，则天数不用减一
        if(isRenewal.equals("1")){
            endTime = DateTimeUtil.getDayEnd(DateTimeUtil.getNextDayDate(currEndTime, monthRuleFeeScaleDTO.getDays()));
        //  如果是开卡，则当前时间算一天，所有天数减一
        } else {
            endTime = DateTimeUtil.getDayEnd(DateTimeUtil.getNextDayDate(currEndTime, monthRuleFeeScaleDTO.getDays()-1));
        }

        /*2、添加购买记录*/
        CardRecord cardRecord = new CardRecord();
        cardRecord.setDayBeginTime(monthRuleFeeScaleDTO.getBeginTime());
        cardRecord.setDayEndTime(monthRuleFeeScaleDTO.getEndTime());
        cardRecord.setCustomerId(loginUser.getCustomerId()); //  客户id
        cardRecord.setOrderCode(orderCode);    //  订单号
        cardRecord.setReceivableAmount(form.getReceivableAmount());    //  应收金额
        cardRecord.setPaidAmount(paidAmount);  //  支付金额
        cardRecord.setPayStatus(PayStatusEnum.ARREARAGE.getCode());    //  支付状态（0：待支付，1：已支付，2：取消支付）
        if(form.getUniformRentType().equals(100) || form.getUniformRentType().equals(110)){
            cardRecord.setCardType(form.getUniformRentType());   //  卡类型（1：普通月租卡，2：定制卡，3时长卡， 4：充值，100：白天卡-月租，110：夜间卡-月租）
        } else {
            cardRecord.setCardType(1);   //  卡类型（1：普通月租卡，2：定制卡，3时长卡， 4：充值，100：白天卡-月租，110：夜间卡-月租）
        }
        cardRecord.setTicketId(form.getCustTicketId());
        cardRecord.setMonthRentType(form.getMonthRentType());    //  月租卡的月租类型
        cardRecord.setBeginTime(startTime);
        cardRecord.setExpireTime(endTime);
        cardRecord.setParkSource(parkInfo.getParkSource());
        cardRecord.setCarNumber(car.getCarNumber());
        cardRecord.setUniformRentType(form.getUniformRentType());
        cardRecord.setMobilePhone(customerDTO.getMobilePhone());
        cardRecordDao.insert(cardRecord);

        /*3、添加购买记录关联的停车场*/
        CardRecordPark cardRecordPark = new CardRecordPark();
        cardRecordPark.setCardRecordId(cardRecord.getId());
        cardRecordPark.setParkId(form.getParkId());
        cardRecordPark.setParkMonthAmount(monthRuleFeeScaleDTO.getParkAmount());
        cardRecordPark.setMonthDivide(parkInfo.getMonthDivide());
        cardRecordPark.setParkMonthPaidAmount(paidParkAmount);
        cardRecordParkDao.insert(cardRecordPark);

        /*4、支付*/
        JSONObject attach = new JSONObject();
        attach.put("carId", form.getCarId());
        attach.put("isRenewal", isRenewal);
        attach.put("parkId", form.getParkId());
        attach.put("parkMonthId", parkMonthId);

        //  测试环境金额
        paidAmount = payTest ? new BigDecimal("0.01") : paidAmount;    //  支付金额

        return WeChatUtil.wxPay(customerDTO.getOpenid(), buyMonthCardNotifyUrl, paidAmount, orderCode, attach.toJSONString(), "购买月卡");
    }

    /**
     * 微信支付回调-购买普通月卡
     */
    @Override
    @Transactional
    public String buyMonthCardCallback(String callbackStr) {
        //  解析微信返回值
        Map<String, String> callbackMap = null;
        try {
            callbackMap = XmlUtil.parseXML(callbackStr);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 支付成功
        if ("SUCCESS".equals(callbackMap.get("return_code")) && "SUCCESS".equals(callbackMap.get("result_code"))) {
            String orderCode = callbackMap.get("out_trade_no");    //  订单号
            try {
                //  修改购买会员卡订单状态
                log.info("缓存订单号：{}", requestCatch);
                if(requestCatch.contains(orderCode)){
                    ExceptionUtil.businessException("微信支付回调-购买普通月卡-订单号【" + orderCode + "】正在处理");
                } else {
                    requestCatch.add(orderCode);
                }
                log.info("订单号：" + orderCode);

                //  订单参数
                String attach = StringEscapeUtils.unescapeJava(callbackMap.get("attach"));  //  附加数据，在处理字符串之前，先将字符串去除转义
                JSONObject attachJB = JSONObject.parseObject(attach);
                Long carId = Long.valueOf(attachJB.getString("carId"));
                String isRenewal = attachJB.getString("isRenewal");
                Long parkId = Long.valueOf(attachJB.getString("parkId"));
                String parkMonthId = attachJB.getString("parkMonthId");

                //  查询订单信息
                CardRecordDTO cardRecordDTO = cardRecordDao.getCardRecordByOrderCode(orderCode);
                if(cardRecordDTO == null) {
                    ExceptionUtil.businessException("订单号" + orderCode + "错误");
                }
                //  如果已经支付，返回true
                if(cardRecordDTO.getPayStatus() == PayStatusEnum.PAID.getCode()){
                    log.info("订单号" + orderCode + "已经支付，不能重复支付");
                    return "SUCCESS";
                }

                //  客户
                CustomerDTO customerDTO = customerDao.getCustomerById(cardRecordDTO.getCustomerId());
                log.info("车主信息：{}", customerDTO);
                //  停车场
                ParkInfo parkInfo = parkInfoDao.selectById(parkId);
                log.info("停车场信息：{}", parkInfo);
                //  车牌
                Car car = carDao.selectById(carId);
                log.info("车辆信息：{}", car);

                //  道尔、腾达等停车场月租规则，1，2，3为立码停车月租规则
                if(!cardRecordDTO.getMonthRentType().equals(1) && !cardRecordDTO.getMonthRentType().equals(2) && !cardRecordDTO.getMonthRentType().equals(3)) {
                    CardRecordParkDTO cardRecordParkDTO = cardRecordParkDao.getCardRecordParkByRecordId(cardRecordDTO.getId());
                    //  购买道尔月卡
                    if(cardRecordDTO.getParkSource().equals(3)){
                        Map<String, Object> resultMap = new HashMap<>();
                        //  如果有购买记录，则续卡
                        if(isRenewal.equals("1")){
                            resultMap = DaoerApiUtil.monthRenewal(parkInfo.getBolianParkId(), car.getCarNumber(), cardRecordDTO.getBeginTime(), cardRecordDTO.getExpireTime(), cardRecordParkDTO.getParkMonthPaidAmount());
                            //  如果没有购买记录，则添加
                        } else  {
                            resultMap = DaoerApiUtil.buyMonthCard(parkInfo.getBolianParkId(), car.getCarNumber(), cardRecordDTO.getMonthRentType(), cardRecordDTO.getBeginTime(), cardRecordDTO.getExpireTime(), cardRecordParkDTO.getParkMonthPaidAmount(), customerDTO.getNickname(), customerDTO.getMobilePhone());
                        }
                        //  如果办卡成功，则向停车场支付费用，否则不支付费用
                        if(resultMap.get("status").equals(1)){
                            //  泊链向停车场支付月卡金额
                            BigDecimal amount  = payTest ? new BigDecimal("0.01") : cardRecordParkDTO.getParkMonthPaidAmount();
//                            BolianUtil.pay(car.getCarNumber(), parkInfo.getBolianParkId(), amount);
                        }
                        //  购买腾达月卡
                    } else if(cardRecordDTO.getParkSource().equals(4)){
                        TengdaForm tengdaForm = new TengdaForm();
                        //  如果有购买记录，则续卡
                        if(isRenewal.equals("1")){
                            tengdaForm = TengdaUtil.monthRenewal(parkMonthId, parkInfo.getBolianParkId(), car.getCarNumber(), cardRecordDTO.getMonthRentType(), cardRecordParkDTO.getParkMonthPaidAmount(), cardRecordDTO.getBeginTime(), cardRecordDTO.getExpireTime());
                            //  如果没有购买记录，则添加
                        } else {
                            tengdaForm = TengdaUtil.buyMonthCard(parkInfo.getBolianParkId(), car.getCarNumber(), cardRecordDTO.getMonthRentType(), cardRecordParkDTO.getParkMonthPaidAmount(), cardRecordDTO.getBeginTime(), cardRecordDTO.getExpireTime());
                            CarForm carForm = JSONObject.toJavaObject(tengdaForm.getDataItems().get(0), CarForm.class);
                            parkMonthId = carForm.getUUID();
                        }
                        //  如果办卡成功，则向停车场支付费用，否则不支付费用
                        if(tengdaForm.getCode().equals(1)) {
                            //  泊链向停车场支付月卡金额
                            BigDecimal amount = payTest ? new BigDecimal("0.01") : cardRecordParkDTO.getParkMonthPaidAmount();
//                            BolianUtil.pay(car.getCarNumber(), parkInfo.getBolianParkId(), amount);
                        }
                    } else {
                        log.error("停车场来源【{}】错误", cardRecordDTO.getParkSource());
                    }
                }

                /*2、记录使用的优惠券*/
                CustTicket custTicket = new CustTicket();
                if(cardRecordDTO.getTicketId() != null) {
                    custTicket = custTicketDao.selectById(cardRecordDTO.getTicketId());
                    custTicket.setStatus(1);
                    custTicket.setTipsStatus(0);
                    custTicket.setUpdateTime(new Date());
                    custTicketDao.updateById(custTicket);
                }

                //  会员卡
                CardDTO cardDTO = cardDao.getCustomerCardByCarIdAndParkId(cardRecordDTO.getCustomerId(), carId, parkId);
                //  如果所选车牌购买过所选停车场的会员卡，就续时
                Card card = new Card();
                if(cardDTO != null){
                    //更新会员卡信息
                    BeanUtils.copyProperties(cardDTO, card);
                    card.setCardType(cardRecordDTO.getCardType());
                    card.setParkMonthId(parkMonthId);
                    cardDao.updateById(card);

                    //  修改车辆服务实时状态关联的停车场的有效日期
                    CardPark cardPark = new CardPark();
                    cardPark.setStartTime(cardRecordDTO.getBeginTime());
                    cardPark.setExpireTime(cardRecordDTO.getExpireTime()); //  过期日期
                    cardPark.setDayBeginTime(cardRecordDTO.getDayBeginTime());
                    cardPark.setDayEndTime(cardRecordDTO.getDayEndTime());
                    cardPark.setParkMonthTypeCode(cardRecordDTO.getMonthRentType());
                    LambdaUpdateWrapper<CardPark> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
                    lambdaUpdateWrapper.eq(CardPark::getCardId, cardDTO.getId());  //  车辆服务实时状态
                    lambdaUpdateWrapper.eq(CardPark::getParkId, parkId);    //  停车场id
                    cardParkDao.update(cardPark, lambdaUpdateWrapper);
                    //  如果还没购买过该停车场月卡，则添加
                } else {
                    //  添加车辆服务实时状态
                    card.setParkMonthId(parkMonthId); //车场月租车编号
                    card.setCustomerId(cardRecordDTO.getCustomerId());   //  客户id
                    card.setCarId(carId);    //  车牌号id
                    card.setCarNumber(car.getCarNumber());
                    card.setCardType(cardRecordDTO.getCardType());
                    cardDao.insert(card);

                    //  添加车辆服务实时状态关联的停车场
                    CardPark cardPark = new CardPark();
                    cardPark.setCardId(card.getId());   //  车辆服务实时状态
                    cardPark.setParkId(parkId); //  停车场id
                    cardPark.setStartTime(cardRecordDTO.getBeginTime());
                    cardPark.setExpireTime(cardRecordDTO.getExpireTime()); //  过期日期
                    cardPark.setDayBeginTime(cardRecordDTO.getDayBeginTime());
                    cardPark.setDayEndTime(cardRecordDTO.getDayEndTime());
                    cardPark.setParkMonthTypeCode(cardRecordDTO.getMonthRentType());
                    cardParkDao.insert(cardPark);
                }

                /*3、修改购买记录信息*/
                CardRecord cardRecord = new CardRecord();
                cardRecord.setTicketId(custTicket.getTicketId());
                cardRecord.setId(cardRecordDTO.getId());
                cardRecord.setPayStatus(PayStatusEnum.PAID.getCode());
                cardRecord.setCardId(card.getId());
                cardRecordDao.updateById(cardRecord);

                //微信公众号推送消息
                if (customerDTO != null && customerDTO.getUnionid() != null) {
                    OpenServiceMessage message = new OpenServiceMessage();
                    message.setUnionid(customerDTO.getUnionid());
                    message.setServiceType("停车月租服务");
                    long distanceDays = DateTimeUtil.getDistanceDays(cardRecordDTO.getBeginTime(), cardRecordDTO.getExpireTime());
                    message.setDuration(distanceDays + 1 + "天");    //  当天算一天，所以加一天
                    message.setParkName(parkInfo.getParkName());

                    //服务开通通知
                    mpMessageUtil.openServiceMessage(message, MDC.get("requestId"));
                }

                log.info("------------购买普通月卡-微信支付回调结束");
            } finally {
                //  清除缓存
                requestCatch.remove(orderCode);
            }
        }

        return WeChatUtil.wxpayCallbackResult(true);
    }

    /**
     * 购买定制卡
     */
    @Override
    @Transactional
    public Map<String, Object> buyCustomizeCard(CustomizeCardBuyForm form) {
        LoginUser loginUser = JwtUtil.getLoginUser(request);

        /*1、校验数据完整性*/
        //  查询客户
        CustomerDTO customerDTO = customerDao.getCustomerById(loginUser.getCustomerId());
        if (customerDTO == null) {
            ExceptionUtil.businessException("客户：" + loginUser.getCustomerId() + "不存在");
        }
        if (StringUtils.isBlank(customerDTO.getMobilePhone())) {
            ExceptionUtil.businessException("请绑定手机号");
        }
        //  校验停车场月租类型
        for (Long parkId : form.getParkIdList()) {
            //  获取停车场的月租收费标准
            MonthRuleFeeScaleDTO monthRuleFeeScaleDTO = monthRuleMapper.getParkMonthRuleFeeScaleByMonthRentType(parkId, form.getMonthRentType().getCode());
            if (monthRuleFeeScaleDTO == null) {
                ExceptionUtil.businessException("停车场" + parkId + "没有" + form.getMonthRentType() + "的月租类型");
            }
        }
        //  根据规则id和月租类型查询收费标准
        List<CustomizeRuleFeeScaleDTO> customizeRuleFeeScaleDTOList = customizeRuleFeeScaleDao.getCustomizeRuleFeeScaleByParkNum(form.getParkIdList().size());
        if (customizeRuleFeeScaleDTOList.size() == 0) {
            ExceptionUtil.businessException("所选停车场没有收费标准");
        }
        BigDecimal paidAmount = form.getPaidAmount();   //  支付金额
        //  车牌
        Car car = carDao.selectById(form.getCarId());
        //  所选定制卡的金额
        CustomizeRuleFeeScaleMobileVO customizeRuleFeeScaleMobileVO = customizeRuleService.computePrice(form.getParkIdList());
        if(payTest){    //  测试金额
            paidAmount = new BigDecimal("0.01");    //  支付金额
        } else {
            //  优惠券
            CustTicketDTO custTicket = custTicketDao.getById(form.getCustTicketId());

            if(form.getMonthRentType() == MonthRentTypeEnum.MONTH){
                //  校验支付金额
                checkPaidAmount(paidAmount, customizeRuleFeeScaleMobileVO.getMonthTotalAmount(), custTicket);
            }
            if(form.getMonthRentType() == MonthRentTypeEnum.QUARTER){
                //  校验支付金额
                checkPaidAmount(paidAmount, customizeRuleFeeScaleMobileVO.getQuarterTotalAmount(), custTicket);
            }
            if(form.getMonthRentType() == MonthRentTypeEnum.YEAR){
                //  校验支付金额
                checkPaidAmount(paidAmount, customizeRuleFeeScaleMobileVO.getYearTotalAmount(), custTicket);
            }
        }

        /*2、添加购买记录*/
        //  获取多个停车场普通月租金额总和
        BigDecimal receivableAmount = monthRuleFeeScaleMapper.getMonthRuleAmountByParkIdList(form.getParkIdList(), form.getMonthRentType().getCode());
        //  所选卡的收费标准
        CustomizeRuleFeeScaleDTO customizeRuleFeeScaleDTO = customizeRuleFeeScaleDTOList.stream().filter(customizeRuleFeeScale -> customizeRuleFeeScale.getMonthRentType() == form.getMonthRentType().getCode()).findFirst().get();
        String orderCode = ChinaumsUtil.getMerOrderId("DZK-");  //    订单号
        CardRecord cardRecord = new CardRecord();
        cardRecord.setCustomerId(loginUser.getCustomerId()); //  客户id
        cardRecord.setOrderCode(orderCode);    //  订单号
        cardRecord.setPaidAmount(paidAmount);  //  支付金额
        cardRecord.setPayStatus(PayStatusEnum.ARREARAGE.getCode());    //  支付状态（0：待支付，1：已支付，2：取消支付）
        cardRecord.setCardType(CardTypeEnum.CUSTOMIZE.getCode());   //  卡类型（1：普通月租卡，2：定制卡，3时长卡）
        cardRecord.setReceivableAmount(receivableAmount);   //  应收金额
        cardRecord.setTicketId(form.getCustTicketId());
        cardRecord.setMonthRentType(form.getMonthRentType().getCode());    //  月租卡的月租类型
        cardRecord.setCustomizeCardRate(customizeRuleFeeScaleDTO.getDiscountRate());    //  定制卡优惠比列
        cardRecord.setCarNumber(car.getCarNumber());
        cardRecord.setMobilePhone(customerDTO.getMobilePhone());
        cardRecordDao.insert(cardRecord);

        /*3、添加会员卡购买记录停车场*/
        for(Long parkId: form.getParkIdList()){
            //  获取停车场的月租收费标准
            MonthRuleFeeScaleDTO monthRuleFeeScaleDTO = monthRuleMapper.getParkMonthRuleFeeScaleByMonthRentType(parkId, form.getMonthRentType().getCode());

            CardRecordPark cardRecordPark = new CardRecordPark();
            cardRecordPark.setCardRecordId(cardRecord.getId());
            cardRecordPark.setParkId(parkId);
            cardRecordPark.setParkMonthAmount(monthRuleFeeScaleDTO.getAmount());
            cardRecordParkDao.insert(cardRecordPark);
        }

        /*4、支付*/
        JSONObject attach = new JSONObject();
        attach.put("carId", form.getCarId());
        attach.put("monthRentType", form.getMonthRentType());
        attach.put("cardRecordId", cardRecord.getId());
        attach.put("custTicketId", form.getCustTicketId());

        //  下单
        return WeChatUtil.wxPay(customerDTO.getOpenid(), buyCustomizeCardNotifyUrl, paidAmount, orderCode, attach.toJSONString(), "购买定制卡");
    }

    /**
     * 微信支付回调-购买定制月卡
     */
    @Override
    @Transactional
    public String buyCustomizeCardCallback(String callbackStr) {
        //  解析微信返回值
        Map<String, String> callbackMap = null;
        try {
            callbackMap = XmlUtil.parseXML(callbackStr);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 支付成功
        if ("SUCCESS".equals(callbackMap.get("return_code")) && "SUCCESS".equals(callbackMap.get("result_code"))) {
            //  修改购买会员卡订单状态
            String orderCode = callbackMap.get("out_trade_no");    //  订单号
            log.info("订单号：" + orderCode);
            String attach = callbackMap.get("attach");  //  附加数据

            //  处理购买的定制月卡
            buyCustomizeCardCallbackHandle(orderCode, attach);

            log.info("------------购买定制月卡-微信支付回调结束");
        }
        return WeChatUtil.wxpayCallbackResult(true);
    }

    /**
     * 处理购买的定制月卡
     */
    public String buyCustomizeCardCallbackHandle(String orderCode, String attach){
        try{
            CardRecordDTO cardRecordDTO = cardRecordDao.getCardRecordByOrderCode(orderCode);
            if(cardRecordDTO == null){
                ExceptionUtil.businessException("订单号" + orderCode + "错误");
            }
            //  如果已经支付，返回true
            if(cardRecordDTO.getPayStatus() == PayStatusEnum.PAID.getCode()){
                log.info("订单号" + orderCode + "已经支付，不能重复支付");
                return "SUCCESS";
            }

            //  添加会员卡关联的停车场
            attach = StringEscapeUtils.unescapeJava(attach);    //  在处理字符串之前，先将字符串去除转义
            JSONObject attachJB = JSONObject.parseObject(attach);
            Long custocmerId = cardRecordDTO.getCustomerId(); //  Long.valueOf(attachJB.getString("custocmerId"));
            Long carId = Long.valueOf(attachJB.getString("carId"));
            Long cardRecordId = Long.valueOf(attachJB.getString("cardRecordId"));
            MonthRentTypeEnum monthRentType = MonthRentTypeEnum.valueOf(attachJB.getString("monthRentType"));
            String custTicketId = attachJB.getString("custTicketId");
            long distanceDays = DateTimeUtil.getDistanceDays(cardRecordDTO.getBeginTime(), cardRecordDTO.getExpireTime());

            CardRecord cardRecord = new CardRecord();
            if(StringUtils.isNotBlank(custTicketId)){
                Long custTicketId_l = Long.valueOf(custTicketId);
                CustTicket custTicket = custTicketDao.selectById(custTicketId_l);
                custTicket.setStatus(1);
                custTicket.setTipsStatus(0);
                custTicket.setUpdateTime(new Date());
                custTicketDao.updateById(custTicket);
                cardRecord.setTicketId(custTicket.getTicketId());
            }

            cardRecord.setId(cardRecordDTO.getId());
            cardRecord.setPayStatus(PayStatusEnum.PAID.getCode());
            cardRecordDao.updateById(cardRecord);

            //  获取购买记录关联的停车场
            List<CardRecordParkDTO> cardRecordParkList = cardRecordParkDao.getCardRecordParkList(cardRecordId);
            List<Long> parkIdList = cardRecordParkList.stream().map(CardRecordParkDTO::getParkId).collect(Collectors.toList());
            log.info("停车场id集合：" + parkIdList);
            for(Long parkId: parkIdList){
                //  获取停车场的月租收费标准
                MonthRuleFeeScaleDTO monthRuleFeeScaleDTO = monthRuleMapper.getParkMonthRuleFeeScaleByMonthRentType(parkId, monthRentType.getCode());
                if(monthRuleFeeScaleDTO == null){
                    ExceptionUtil.businessException("停车场" + parkId + "没有" + monthRentType +  "的月租类型");
                }

                //  到期日期
                Date expireTime;
                //  根据carId和parkId查询客户车辆服务
                CardDTO cardDTO = cardDao.getCustomerCardByCarIdAndParkId(custocmerId, carId, parkId);
                //  如果车牌购买过所选停车场，并且卡还没到期
                if(cardDTO != null && cardDTO.getExpireTime().getTime() > new Date().getTime()){
                    // 如果卡还未到期，续卡
                    expireTime = DateTimeUtil.getDayEnd(DateTimeUtil.getNextDayDate(cardDTO.getExpireTime(), (int) distanceDays));
                } else {
                    expireTime = DateTimeUtil.getDayEnd(DateTimeUtil.getNextDayDate(new Date(), (int) (distanceDays-1)));
                }

                //  如果所选车牌购买过所选停车场的会员卡，就续时
                if(cardDTO != null){
                    //  修改车辆服务实时状态关联的停车场的有效日期
                    CardPark cardPark = new CardPark();
                    cardPark.setExpireTime(expireTime); //  过期日期
                    LambdaUpdateWrapper<CardPark> lambdaUpdateWrapper = new LambdaUpdateWrapper();
                    lambdaUpdateWrapper.eq(CardPark::getCardId, cardDTO.getId());  //  车辆服务实时状态
                    lambdaUpdateWrapper.eq(CardPark::getParkId, parkId);    //  停车场id
                    cardParkDao.update(cardPark, lambdaUpdateWrapper);
                } else {
                    //  车牌
                    Car car = carDao.selectById(carId);
                    //  添加车辆服务实时状态
                    List<CardDTO> cardDTOList = cardDao.getByCustomerIdCarId(custocmerId, carId);
                    Long cardId = null;
                    if(cardDTOList.size() == 0){
                        Card card = new Card();
                        card.setCustomerId(custocmerId);   //  客户id
                        card.setCarId(carId);    //  车牌号id
                        card.setCarNumber(car.getCarNumber());
                        card.setCardType(RealtimeCardTypeEnum.MONTH.getCode());
                        cardDao.insert(card);

                        cardId = card.getId();
                    } else {
                        cardId = cardDTOList.get(0).getId();
                    }

                    //  添加车辆服务实时状态关联的停车场
                    CardPark cardPark = new CardPark();
                    cardPark.setCardId(cardId);   //  车辆服务实时状态
                    cardPark.setParkId(parkId); //  停车场id
                    cardPark.setExpireTime(expireTime); //  过期日期
                    cardParkDao.insert(cardPark);
                }
            }

            //  查询客户
            CustomerDTO customerDTO = customerDao.getCustomerById(custocmerId);
            if (customerDTO != null && customerDTO.getUnionid() != null) {
                OpenServiceMessage message = new OpenServiceMessage();
                message.setUnionid(customerDTO.getUnionid());
                message.setServiceType("停车月租服务");
                message.setDuration(distanceDays + "天");
                ParkInfo parkInfo = parkInfoDao.selectById(parkIdList.get(0));
                String parkName = parkInfo.getParkName() + "等" + parkIdList.size() + "个停车场";
                message.setParkName(parkName);

                String requestId = MDC.get("requestId");

                //服务开通通知
               mpMessageUtil.openServiceMessage(message,requestId);
            }
        } catch (Exception e) {
            log.error("发送消息失败【{}】", e.getMessage());
        }

        return "SUCCESS";
    }

    /**
     * 购买时长卡
     */
    @Override
    @Transactional
    public Map<String, Object> buyDurationCard(DurationCardBuyForm form) {
        LoginUser loginUser = JwtUtil.getLoginUser(request);

        /*1、校验数据完整性*/
        BigDecimal paidAmount = form.getPaidAmount();   //  支付金额
        //  查询客户
        CustomerDTO customerDTO = customerDao.getCustomerById(loginUser.getCustomerId());
        if(customerDTO == null){
            ExceptionUtil.businessException("客户：" + loginUser.getCustomerId() + "不存在");
        }
        if(StringUtils.isBlank(customerDTO.getMobilePhone())){
            ExceptionUtil.businessException("请绑定手机号");
        }
        //  根据id查询时长规则收费标准
        DurationRuleFeeScaleDTO durationRuleFeeScaleDTO = durationRuleFeeScaleMapper.getDurationRuleFeeScale(form.getDurationRuleFeeScaleId(), form.getDurationRuleId());
        if(durationRuleFeeScaleDTO == null){
            ExceptionUtil.businessException("时长规则" + form.getDurationRuleId() + "没有收费标准，或收费标准id" + form.getDurationRuleFeeScaleId() + "错误");
        }
        //  根据规则id查询时长规则停车场
        List<DurationRuleParkDTO> durationRuleParkList = durationRuleParkMapper.getDurationRuleParkByRuleId(form.getDurationRuleId(), null);
        if(durationRuleParkList.size() == 0){
            ExceptionUtil.businessException("没有关联的停车场");
        }

        /*2、添加购买记录*/
        String orderCode = ChinaumsUtil.getMerOrderId("SCK-");  //    订单号
        if(payTest){
            paidAmount = new BigDecimal("0.01");
        } else {
            //  优惠券
            CustTicketDTO custTicket = custTicketDao.getById(form.getCustTicketId());
            //  校验支付金额
            checkPaidAmount(paidAmount, durationRuleFeeScaleDTO.getAmount(), custTicket);
        }
        CardRecord cardRecord = new CardRecord();
        cardRecord.setCustomerId(loginUser.getCustomerId()); //  客户id
        cardRecord.setOrderCode(orderCode);    //  订单号
        cardRecord.setPaidAmount(paidAmount);  //  支付金额
        cardRecord.setPayStatus(PayStatusEnum.ARREARAGE.getCode());    //  支付状态（0：待支付，1：已支付，2：取消支付）
        cardRecord.setCardType(CardTypeEnum.DURATION.getCode());   //  卡类型（1：普通月租卡，2：定制卡，3时长卡）
        cardRecord.setTicketId(form.getCustTicketId());
        cardRecord.setDuration(durationRuleFeeScaleDTO.getDuration());
        cardRecord.setMobilePhone(customerDTO.getMobilePhone());
        cardRecordDao.insert(cardRecord);

        /*3、添加购买记录关联的停车场*/
        List<Long> parkIdList = durationRuleParkList.stream().map(DurationRuleParkDTO::getParkId).collect(Collectors.toList());
        cardRecordParkDao.insertCardPark(cardRecord.getId(), parkIdList);

        /*4、支付*/
        //  如果支付金额为0，则不走微信支付
        if (paidAmount.compareTo(new BigDecimal(0)) <= 0) {
            JSONObject attach = new JSONObject();
            attach.put("durationRuleId", form.getDurationRuleId());
            attach.put("duration", durationRuleFeeScaleDTO.getDuration());
            attach.put("custTicketId", form.getCustTicketId());

            buyDurationCardCallbackHandle(orderCode, attach.toJSONString());

            return null;
        } else {
            //  支付
            JSONObject attach = new JSONObject();
            attach.put("durationRuleId", form.getDurationRuleId());
            attach.put("duration", durationRuleFeeScaleDTO.getDuration());
            attach.put("custTicketId", form.getCustTicketId());

            //  下单
            return WeChatUtil.wxPay(customerDTO.getOpenid(), buyDurationCardNotifyUrl, paidAmount, orderCode, attach.toJSONString(), "购买时长卡");
        }
    }

    /**
     * 微信支付回调-购买时长卡
     */
    @Override
    @Transactional
    public String buyDurationCardCallback(String callbackStr) {
        //  解析微信返回值
        Map<String, String> callbackMap = null;
        try {
            callbackMap = XmlUtil.parseXML(callbackStr);
        } catch (Exception e) {
            e.printStackTrace();
        }

        log.info("购买时长卡-微信支付回调：" + callbackMap);
        // 支付成功
        if ("SUCCESS".equals(callbackMap.get("return_code")) && "SUCCESS".equals(callbackMap.get("result_code"))) {
            //  修改购买会员卡订单状态
            String orderCode = callbackMap.get("out_trade_no");    //  订单号
            //  自定义参数
            String attach = callbackMap.get("attach");

            //  购买时长卡处理
            buyDurationCardCallbackHandle(orderCode, attach);

            log.info("------------购买时长卡-微信支付回调结束");
        }
        return WeChatUtil.wxpayCallbackResult(true);
    }

    /**
     *  处理购买的时长卡
     */
    public String buyDurationCardCallbackHandle(String orderCode, String attach){
        CardRecordDTO cardRecordDTO = cardRecordDao.getCardRecordByOrderCode(orderCode);
        if(cardRecordDTO == null){
            ExceptionUtil.businessException("订单号" + orderCode + "错误");
        }
        //  如果已经支付，返回true
        if(cardRecordDTO.getPayStatus() == PayStatusEnum.PAID.getCode()){
            log.info("订单号" + orderCode + "已经支付，不能重复支付");
            return "SUCCESS";
        }

        JSONObject attachJB = JSONObject.parseObject(attach);
        Long custocmerId = cardRecordDTO.getCustomerId(); //  Long.valueOf(attachJB.getString("custocmerId"));
        Long durationRuleId = Long.valueOf(attachJB.getString("durationRuleId"));
        Long duration = Long.valueOf(attachJB.getString("duration"));

        //  根据规则id查询时长规则停车场
        List<DurationRuleParkDTO> durationRuleParkList = durationRuleParkMapper.getDurationRuleParkByRuleId(durationRuleId, null);
        if(durationRuleParkList.size() == 0){
            ExceptionUtil.businessException("没有关联的停车场");
        }
        List<Long> parkIdList = durationRuleParkList.stream().map(DurationRuleParkDTO::getParkId).collect(Collectors.toList());
        String custTicketId = attachJB.getString("custTicketId");

        CardRecord cardRecord = new CardRecord();

        if(StringUtils.isNotBlank(custTicketId)){
            Long custTicketId_l = Long.valueOf(custTicketId);
            CustTicket custTicket = custTicketDao.selectById(custTicketId_l);
            custTicket.setStatus(1);
            custTicket.setTipsStatus(0);
            custTicket.setUpdateTime(new Date());
            custTicketDao.updateById(custTicket);

            cardRecord.setTicketId(custTicket.getTicketId());
        }
        cardRecord.setId(cardRecordDTO.getId());
        cardRecord.setPayStatus(PayStatusEnum.PAID.getCode());
        cardRecordDao.updateById(cardRecord);

        //  添加车辆服务实时状态
        Card card = new Card();
        card.setCustomerId(custocmerId);   //  客户id
        card.setTimeLeft(duration); //  时长
        card.setCardType(RealtimeCardTypeEnum.DURATION.getCode());
        cardDao.insert(card);

        log.info("车场id集合：" + parkIdList);
        //  添加车辆服务实时状态关联的停车场
        for(Long parkId: parkIdList) {
            CardPark cardPark = new CardPark();
            cardPark.setCardId(card.getId());   //  车辆服务实时状态
            cardPark.setParkId(parkId); //  停车场id
            cardParkDao.insert(cardPark);
        }

        //微信公众号发送消息
        //  查询客户
        CustomerDTO customerDTO = customerDao.getCustomerById(custocmerId);
        if (customerDTO != null && customerDTO.getUnionid() != null){
            OpenServiceMessage message = new OpenServiceMessage();
            message.setUnionid(customerDTO.getUnionid());
            message.setServiceType("停车时长服务");
            message.setDuration(duration + "小时");
            ParkInfo parkInfo = parkInfoDao.selectById(parkIdList.get(0));
            String parkName = parkInfo.getParkName() + "等" + parkIdList.size() + "个停车场";
            message.setParkName(parkName);

            String requestId = MDC.get("requestId");

            //服务开通通知
            mpMessageUtil.openServiceMessage(message,requestId);
        }

        return "SUCCESS";
    }

    /**
     * 会员购买之后，判断订单是否支付状态成功
     */
    @Override
    public boolean  validatePayState(String orderCode){
        //  最多查询10次
        for(int i=1; i<=10; i++) {
            log.info("校验购买会员卡订单号{}是否回调成功-第{}次", orderCode, i);

            //  泊链月租
            CardRecordDTO cardRecordDTO = cardRecordDao.getCardRecordByOrderCode(orderCode);
            if(cardRecordDTO !=null && cardRecordDTO.getPayStatus().equals(PayStatusEnum.PAID.getCode())){
                return true;
            }

            //  睡眠一秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        log.error("购买会员卡订单号{}10秒无回调", orderCode);

        return false;
    }

    /**
     * 是否有会员卡
     */
    @Override
    public HasCardDTO hasCard(CardHasForm cardHasForm) {
        HasCardDTO hasCardDTO = new HasCardDTO();
        hasCardDTO.setOrderCardTypeEnum(OrderCardTypeEnum.NO);

        //  根据车牌号获取客户车辆
        CarDTO carDTO = carDao.getCustCarByCarNumber(cardHasForm.getCarNumber());
        if(carDTO == null){
            log.error("非立码停车绑定车牌【" + cardHasForm.getCarNumber() + "】，不做处理");
            hasCardDTO.setMassage("非立码停车绑定车牌【" + cardHasForm.getCarNumber() + "】，不做处理");
            return hasCardDTO;
        }
        hasCardDTO.setCustomerId(carDTO.getCustomerId());   //  客户id

        //  根据carId和parkId查询客户车辆停车场月租服务
        CardDTO monthCardDTO = cardDao.getMonthCardByCarIdParkId(carDTO.getId(), cardHasForm.getParkId());
        //  月租会员卡
        if(monthCardDTO != null) {
            hasCardDTO.setTimeLeft(0L);
            //  白天卡
            if(monthCardDTO.getCardType().equals(100)){
                hasCardDTO.setOrderCardTypeEnum(OrderCardTypeEnum.DAYMONTH);
            //  夜间卡
            } else if(monthCardDTO.getCardType().equals(110)){
                hasCardDTO.setOrderCardTypeEnum(OrderCardTypeEnum.NIGHTMONTH);
            //  月租卡
            } else {
                hasCardDTO.setOrderCardTypeEnum(OrderCardTypeEnum.MONTH);
            }
            HasCardDTO.UsedCard usedCard = new HasCardDTO.UsedCard();
            usedCard.setId(monthCardDTO.getId());
            hasCardDTO.setUsedCardList(Arrays.asList(usedCard));
            return hasCardDTO;
        }

        /*3、余额*/
        CardDTO cardDTO = cardDao.getBalance(carDTO.getCustomerId());
        if(cardDTO != null && cardHasForm.getAmount() != null && cardDTO.getCardBalance().compareTo(cardHasForm.getAmount()) >= 0){
            log.info("判断车牌是否有会员卡-余额充足【{}】", cardDTO.getCardBalance());
            hasCardDTO.setOrderCardTypeEnum(OrderCardTypeEnum.BALANCE);
            HasCardDTO.UsedCard usedCard = new HasCardDTO.UsedCard();
            usedCard.setId(cardDTO.getId());
            usedCard.setOldBalance(cardDTO.getCardBalance());
            hasCardDTO.setUsedCardList(Arrays.asList(usedCard));
        } else if(cardDTO != null && cardHasForm.getAmount() != null) {
            log.info("判断车牌是否有会员卡-余额不足【{}】，应支付【{}】", cardDTO.getCardBalance(), cardHasForm.getAmount());
        } else if (cardDTO != null && cardHasForm.getAmount() == null) {
            log.error("判断车牌是否有会员卡-应支付金额为空，不能判断会员卡");
        } else  {
            log.info("判断车牌是否有会员卡-没有会员卡");
        }

        return hasCardDTO;
    }

    /**
     * 重新设置会员和车牌到泊链
     */
    public void resetUserAndCarToBoLian(Long custocmerId){
        //获取客户车辆
        List<CarDTO> carList = carDao.getCustomerCarList(custocmerId);
        //  上传会员信息到泊链
        boolean addUserFlag = BolianUtil.addUserToBoLian(custocmerId, carList.get(0).getCarNumber());

        //  修改客户的泊链状态
        Customer customer = new Customer();
        customer.setId(custocmerId);
        customer.setIsVip(WhetherEnum.YES.getCode());   //  是否是会员（YES：是,NO：否）
        customer.setIsToBolian(addUserFlag ? WhetherEnum.YES.getCode() : WhetherEnum.NO.getCode());    //  是否上传到泊链（YES：是,NO：否）
        customerDao.updateById(customer);

        //  上传客户，跳过刚才上传的车牌
        for (int i = 1; i < carList.size(); i++) {
            //  添加客户新车牌到泊链
            boolean addUserCarFlag = BolianUtil.addUserCarNumberToBoLian(custocmerId, carList.get(i).getCarNumber());
            //  修改车牌的泊链状态
            if (addUserFlag && addUserCarFlag) {
                Car car = new Car();
                car.setId(carList.get(i).getId());
                car.setIsToBolian(WhetherEnum.YES.getCode());
                carDao.updateById(car);
            }
        }
    }

    /**
     * 校验支付金额
     * @param paidAmount 实付金额
     * @param originalAmount 原始金额
     * @param custTicket    客户优惠券
     */
    void checkPaidAmount(BigDecimal paidAmount, BigDecimal originalAmount, CustTicketDTO custTicket) {
        //  应收金额
        BigDecimal receivableAmount = new BigDecimal(0);
        if (custTicket != null) {
            //  减免金额
            if (custTicket.getPreferentialType().equals(1)) {
                //  应付金额
                receivableAmount = originalAmount.subtract(custTicket.getPreferentialMoney());
            }
            //  折扣
            if (custTicket.getPreferentialType().equals(2)) {
                //  折扣金额
                BigDecimal preferentialMoney = originalAmount.multiply(custTicket.getPreferentialMoney());
                //  应付金额
                receivableAmount = originalAmount.subtract(preferentialMoney);
            }
        }
        if (receivableAmount.compareTo(new BigDecimal(0)) > 0 && paidAmount.compareTo(receivableAmount) != 0) {
            ExceptionUtil.businessException("金额不正确");
        }
    }

    @Override
    public RechargeInfoVO getUserRechargeInfo() {
        LoginUser loginUser = JwtUtil.getLoginUser(request);
        RechargeInfoVO rechargeInfo = new RechargeInfoVO();
        /**查询用户充值信息*/
        Double sum = cardRecordDao.getUserRechargeInfo(loginUser.getCustomerId());
        if (sum == null){
            sum = 0D;
        }
        rechargeInfo.setSumAmount(new BigDecimal(sum));
        /**查询余额*/
        CardDTO balance = cardDao.getBalance(loginUser.getCustomerId());
        if (balance != null){
            rechargeInfo.setCardBalance(balance.getCardBalance());
        }
        /**查询余额交易记录总数量*/
        Long count = orderTradeRecordDao.getOrderTradeRecordCount(loginUser.getCustomerId());
        rechargeInfo.setSumCount(count);

        return rechargeInfo;
    }

}
